Passed
Push — master ( d286b7...24e4a5 )
by Jan
04:36
created

datatables.js ➔ deparam   F

Complexity

Conditions 35

Size

Total Lines 57
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 35
eloc 42
c 0
b 0
f 0
dl 0
loc 57
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like datatables.js ➔ deparam often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * Symfony DataTables Bundle
3
 * (c) Omines Internetbureau B.V. - https://omines.nl/
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author Niels Keurentjes <[email protected]>
9
 */
10
11
(function($) {
12
    /**
13
     * Initializes the datatable dynamically.
14
     */
15
    $.fn.initDataTables = function(config, options) {
16
17
        //Update default used url, so it reflects the current location (useful on single side apps)
18
        $.fn.initDataTables.defaults.url = window.location.origin + window.location.pathname;
19
20
        var root = this,
21
            config = $.extend({}, $.fn.initDataTables.defaults, config),
22
            state = ''
23
        ;
24
25
        // Load page state if needed
26
        switch (config.state) {
27
            case 'fragment':
28
                state = window.location.hash;
29
                break;
30
            case 'query':
31
                state = window.location.search;
32
                break;
33
        }
34
        state = (state.length > 1 ? deparam(state.substr(1)) : {});
35
        var persistOptions = config.state === 'none' ? {} : {
36
            stateSave: true,
37
            stateLoadCallback: function(s, cb) {
38
                // Only need stateSave to expose state() function as loading lazily is not possible otherwise
39
                return null;
40
            }
41
        };
42
43
        return new Promise((fulfill, reject) => {
44
            // Perform initial load
45
            $.ajax(config.url, {
46
                method: config.method,
47
                data: {
48
                    _dt: config.name,
49
                    _init: true
50
                }
51
            }).done(function(data) {
52
                var baseState;
53
54
                // Merge all options from different sources together and add the Ajax loader
55
                var dtOpts = $.extend({}, data.options, config.options, options, persistOptions, {
56
                    ajax: function (request, drawCallback, settings) {
57
                        if (data) {
58
                            data.draw = request.draw;
59
                            drawCallback(data);
60
                            data = null;
61
                            if (Object.keys(state).length && dt.state != null) {
62
                                var merged = $.extend(true, {}, dt.state(), state);
63
                                dt
64
                                    .order(merged.order)
65
                                    .search(merged.search.search)
66
                                    .page.len(merged.length)
67
                                    .page(merged.start / merged.length)
68
                                    .draw(false);
69
                            }
70
                        } else {
71
                            request._dt = config.name;
72
                            $.ajax(config.url, {
73
                                method: config.method,
74
                                data: request
75
                            }).done(function(data) {
76
                                drawCallback(data);
77
                            })
78
                        }
79
                    }
80
                });
81
82
                root.html(data.template);
83
                dt = $('table', root).DataTable(dtOpts);
84
                if (config.state !== 'none') {
85
                    dt.on('draw.dt', function(e) {
86
                        var data = $.param(dt.state()).split('&');
87
88
                        // First draw establishes state, subsequent draws run diff on the first
89
                        if (!baseState) {
90
                            baseState = data;
91
                        } else {
92
                            var diff = data.filter(el => { return baseState.indexOf(el) === -1 && el.indexOf('time=') !== 0; });
93
                            switch (config.state) {
94
                                case 'fragment':
95
                                    history.replaceState(null, null, window.location.origin + window.location.pathname + window.location.search
96
                                        + '#' + decodeURIComponent(diff.join('&')));
97
                                    break;
98
                                case 'query':
99
                                    history.replaceState(null, null, window.location.origin + window.location.pathname
100
                                        + '?' + decodeURIComponent(diff.join('&') + window.location.hash));
101
                                    break;
102
                            }
103
                        }
104
                    })
105
                }
106
107
                fulfill(dt);
108
            }).fail(function(xhr, cause, msg) {
109
                console.error('DataTables request failed: ' + msg);
110
                reject(cause);
111
            });
112
        });
113
    };
114
115
    /**
116
     * Provide global component defaults.
117
     */
118
    $.fn.initDataTables.defaults = {
119
        method: 'POST',
120
        state: 'fragment',
121
        url: window.location.origin + window.location.pathname
122
    };
123
124
    /**
125
     * Convert a querystring to a proper array - reverses $.param
126
     */
127
    function deparam(params, coerce) {
128
        var obj = {},
129
            coerce_types = {'true': !0, 'false': !1, 'null': null};
130
        $.each(params.replace(/\+/g, ' ').split('&'), function (j, v) {
131
            var param = v.split('='),
132
                key = decodeURIComponent(param[0]),
133
                val,
134
                cur = obj,
135
                i = 0,
136
                keys = key.split(']['),
137
                keys_last = keys.length - 1;
138
139
            if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) {
140
                keys[keys_last] = keys[keys_last].replace(/\]$/, '');
141
                keys = keys.shift().split('[').concat(keys);
142
                keys_last = keys.length - 1;
143
            } else {
144
                keys_last = 0;
145
            }
146
147
            if (param.length === 2) {
148
                val = decodeURIComponent(param[1]);
149
150
                if (coerce) {
151
                    val = val && !isNaN(val) ? +val              // number
152
                        : val === 'undefined' ? undefined         // undefined
153
                            : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
154
                                : val;                                                // string
155
                }
156
157
                if (keys_last) {
158
                    for (; i <= keys_last; i++) {
159
                        key = keys[i] === '' ? cur.length : keys[i];
160
                        cur = cur[key] = i < keys_last
161
                            ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : [])
162
                            : val;
163
                    }
164
165
                } else {
166
                    if ($.isArray(obj[key])) {
167
                        obj[key].push(val);
168
                    } else if (obj[key] !== undefined) {
169
                        obj[key] = [obj[key], val];
170
                    } else {
171
                        obj[key] = val;
172
                    }
173
                }
174
175
            } else if (key) {
176
                obj[key] = coerce
177
                    ? undefined
178
                    : '';
179
            }
180
        });
181
182
        return obj;
183
    }
184
}($));
185